﻿using LibNiconico.NiconicoApi.Internal;
using LibNiconico.NiconicoApi.Internal.Http;
using LibNiconico.NiconicoApi.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LibNiconico.NiconicoApi.HeartBeat
{
    internal class NiconicoHeartBeatClient:INiconicoHeartBeatClient
    {
        public event NiconicoHeartBeatReceivedHandler Received;

        public TimeSpan ReceiveTimeSpan { get; set; }

        private NiconicoAuth _auth;

        private Uri targetUrl;

        private Task receiveLoop;

        private string id;

        private SynchronizationContext synchronizationContext;

        public bool Enable { get; private set; }

        internal NiconicoHeartBeatClient(Uri url, string id, NiconicoAuth auth) : this(url, id, auth, SynchronizationContext.Current) { }

        internal NiconicoHeartBeatClient(Uri url,string id, NiconicoAuth auth,SynchronizationContext synchronizationContext)
        {
            _auth = auth;
            this.targetUrl = url;
            Received = null;
            ReceiveTimeSpan = TimeSpan.FromMinutes(3);
            this.id = id;
            Enable = false;
            this.receiveLoop = null;
            this.synchronizationContext = synchronizationContext;
        }

        public void Start()
        {
            if (receiveLoop == null)
            {
                Enable = true;
                receiveLoop = receiveTask();
            }
        }

        public void Stop()
        {
            Enable = false;
            
        }

        private async Task receiveTask()
        {
            int exceptionCount = 0;
            while (Enable)
            {
                try
                {
                    using (var api = new NiconicoInfoGetApiXmlImpl(targetUrl, NiconicoHttpClient.CreateNiconicoApi(this._auth)))
                    {
                        onReceived(NicoHeartBeatResponse.Parse((await api.GetAsync(new NicoGetHeartBeatQueryInfo(id)).ConfigureAwait(false)).Content));
                    }

#if !NET40
                    await Task.Delay(ReceiveTimeSpan).ConfigureAwait(false);
#else
                    await TaskEx.Delay(ReceiveTimeSpan).ConfigureAwait(false);
#endif
                }
                catch (Exception e)
                {
                    if (exceptionCount > 3)
                    {
                        Enable = false;
                    }

                    exceptionCount++;
                }
            }
            
        }


        private void onReceived(NicoHeartBeatResponse response)
        {
            
                if(synchronizationContext != null)
                {
                    synchronizationContext.Post((s) =>
                    {
                        receivedAction(response);
                    }, null);
                }else{
                    receivedAction(response);
                }
                
            
        }

        private void receivedAction(NicoHeartBeatResponse response)
        {
            if (Received != null)
            {

                Received(new NicoHaertBeatReceivedEventArgs(response));
            }
        }



        public void Dispose()
        {
            
            Stop();
            Received = null;
        }
    }

}
